← Nasir Sharaf · Writing

Grasp

Grasping at the future of programming languages

Years ago, Paul Graham wrote an essay called “What Made Lisp Different,” listing the ten or so features that set Lisp apart from every other language. It was my first introduction to Lisp, and the way Graham told it, Lisp invented most of what we now take for granted, like conditionals and garbage collection. What astounds me is how old it is. John McCarthy created it in the late 1950s, and many, if not most, of its features have since been absorbed into modern languages. Originally published on The Ideasthetician, May 3, 2026. First in a series.

Lisp has kept a small, vocal, dedicated following, enough to earn the derisive “Lisp weenie” for its holy-war veterans. But lately it seems Lisp has been mined of its useful ideas. Peter Norvig, author of Paradigms of AI Programming, said Python “is an acceptable Lisp,” and most AI development has indeed moved from Lisp to Python. No one starts a model today without NumPy, Pandas or PyTorch.

I think the future has finally caught up to Lisp, and it’s time to create the next fifty years of language ideas to trickle into the mainstream. What would that language be like, and what would it be for? This series is an attempt to answer that, and to build it.

Philip Greenspun’s Tenth Rule says any sufficiently complicated C or C++ program contains “an ad hoc, informally-specified, bug-ridden, slow implementation of half of Common Lisp.” It’s funny because it’s true, of Java and Python too. Programmers keep reinventing Lisp because its ideas are genuinely useful.

The plan is to run Greenspun’s Rule in reverse: start with the poorly implemented Lisp, on purpose, and use it as the substrate to grow something new. That Lisp is called Schematic. It isn’t the goal, it’s the foundation. It’s also why features like content addressing go in early. If Grasp promises that program transformations are auditable and reversible, that has to be built into the foundation, not retrofitted. Three pillars follow: graphs as the core data structure, content addressing, and Petri nets.

Graphs as a first-class data structure

Lisp stands for list processing because the language is made entirely of lists. That gives it homoiconicity, macros, and easy domain-specific languages. But why lists? Chuck Moore’s Forth is built on stacks, and Kenneth Iverson’s APL on arrays, infamous as a write-only language for its density. These all seem like arbitrary choices. I think the language of the future should be built on the graph.

Every other data structure is a limitation of a graph. A list is a graph where each node links only to the one before and the one after. A graph can be stored as an array through its adjacency matrix. Add rules about how it may change and you get a stack or a heap. So: Grasp, a graph processing language. List : Lisp :: graph : Grasp.

It goes deeper with homoiconicity. In Lisp, DSLs are possible because the language is its own syntax tree. If list homoiconicity gives you Lisp, graph homoiconicity should give you Lisp, Forth and APL as DSLs, and then further DSLs inside those. Programs already are graphs: the control flow of a concurrent system, the dependency graph of a distributed computation, the message topology of a microservice architecture. Programmers draw these on whiteboards and then encode them awkwardly in callbacks, futures and channels. Making that topology explicit in syntax is the graph equivalent of what Lisp did with lists.

Content addressing

One of the first things a developer does on a new project is set up version control, usually git. There’s an argument for keeping that outside the language, but I’ve always wondered why such a common utility isn’t built in. Under the hood, git is a Merkle tree, and Merkle trees are suspiciously close to syntax trees. Merklized abstract syntax trees do exist. Instead of versioning files, we could version functions and macros. Each node of the program graph is tagged with a hash of its contents, so identity follows meaning rather than file location.

Hashing every node has a more powerful side effect: it makes macros and graph transformations safe, or at least reversible. The usual criticism of macros is that they’re too powerful; it’s easy to build a DSL only your lone Lisp wizard understands. With content addressing, the pre- and post-expansion trees each get their own Merkle root, and the expansion is stored explicitly. You can diff what you wrote against what the macro produced, and trace any expanded expression back to the template that made it. Content addressing makes expansion auditable; Merkle structure makes it navigable.

It also enables a much tighter package registry than PyPI. Dependency hell becomes a different hell of matching hashes instead of version strings, but in the wake of the March 2026 LiteLLM attack, it offers a real defense against supply-chain attacks.

Petri nets

A graph-based language makes graphs easy to represent. The obvious application is neural networks, but a less obvious and more consequential one is Petri nets: a model of concurrency that translates directly into formal specifications. Petri nets are exceptional at modeling distributed systems and checking whether they’re valid, which matters because a whole class of subtle, dangerous bugs only appears when programs run in parallel across machines.

If the Grasp interpreter is a Petri net under the hood, you get a formal specification for free. Developers resist formal methods because writing a spec feels redundant when you could just write the software. In Grasp, writing the program is writing the spec. Run a model check as part of debugging and you get formal verification with no extra work, catching bugs like deadlock, two processes waiting on each other forever, that are too costly to chase in development and devastating in production.

Designing for LLMs

Any language designed in 2026 has to be designed for adoption by language models. The combination of formal methods, content-addressed traceability and the graph structure suits them well, because the core problem with generated code today is how easily it’s insecure. These properties mitigate that at the infrastructure layer, and they help with code and context-window management too.

That’s also the motivation for writing this up. Coverage of AI-assisted programming swings between one-shotted apps that print money and outright refusal. I’d like to show something more honest: AI enabling a project beyond my technical reach on my own, while still needing human guidance and taste to realize. There’s still plenty of mid-hanging fruit left by the people who built the tools we stand on.

So that’s the grand dream: a graph programming language with maximum flexibility and built-in security and validation. Is a language for the next hundred years possible? Is there a future for programming languages at all? We’ll find out together.